package org.kojo.tdrm.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.kojo.tdrm.dao.TaskDao;
import org.kojo.tdrm.entity.Task;
import org.kojo.tdrm.entity.User;
import org.kojo.tdrm.persistence.PMF;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

public class TaskAppService {
	public final static int DONE = 0;
	public final static int ONGOING = 1;
	public final static int TIMEOUT = 2;
	private static Logger log = Logger
			.getLogger(TaskAppService.class.getName());

	public void createTask(String userId, Task task) {
		task.setLastUpdate(new Date());
		PersistenceManager pm = PMF.get().getPersistenceManager();
		User u = pm.getObjectById(User.class, userId);
		u.addTaskSets(task);
		pm.currentTransaction().begin();
		pm.makePersistent(u);
		pm.currentTransaction().commit();
		pm.close();
	}

	public Task findTask(String login, long taskId) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Key parentKey = KeyFactory.createKey(User.class.getSimpleName(), login);
		Key key = KeyFactory.createKey(parentKey, Task.class.getSimpleName(),
				taskId);
		Task t = pm.getObjectById(Task.class, key);
		pm.retrieve(t);
		pm.close();
		return t;
	}

	public void saveTask(Task t) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Key parentKey = KeyFactory.createKey(User.class.getSimpleName(),
				t.getOwnedUserId());
		Key key = KeyFactory.createKey(parentKey, Task.class.getSimpleName(), t
				.getKey().getId());
		Task st = pm.getObjectById(Task.class, key);
		pm.currentTransaction().begin();
		st.setName(t.getName());
		st.setDueDate(t.getDueDate());
		st.setLastUpdate(new Date());
		st.setPriority(st.getPriority());
		st.setState(t.getState());
		st.setRepeatType(t.getRepeatType());
		st.setRepeatEvery(t.getRepeatEvery());
		pm.makePersistent(st);
		pm.currentTransaction().commit();
		pm.close();
	}

	public void updateTaskState(String userId, long taskId, String state) {
		Set<Long> taskIds = new HashSet();
		taskIds.add(taskId);
		this.updateTaskState(userId, taskIds, state);
	}

	public void updateTaskState(String userId, Set<Long> taskIds, String state) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.currentTransaction().begin();
		for (Long taskId : taskIds) {
			Key parentKey = KeyFactory.createKey(User.class.getSimpleName(),
					userId);
			Key key = KeyFactory.createKey(parentKey,
					Task.class.getSimpleName(), taskId);
			Task t = pm.getObjectById(Task.class, key);
			t.setState(this.getStateCode(state));
			t.setLastUpdate(new Date());
			pm.makePersistent(t);
		}
		pm.currentTransaction().commit();
		pm.close();
	}

	public void deleteTask(String userId, long id) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Key parentKey = KeyFactory
				.createKey(User.class.getSimpleName(), userId);
		Key key = KeyFactory.createKey(parentKey, Task.class.getSimpleName(),
				id);
		Task t = pm.getObjectById(Task.class, key);
		pm.currentTransaction().begin();
		pm.deletePersistent(t);
		pm.currentTransaction().commit();
		pm.flush();
		pm.close();
	}

	public void clearCompleteTask(String loginName) {
		List<Task> lsTask = null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery("select from " + Task.class.getName()
				+ " where (ownedUser == u) && (state== s) && (repeatType == r)");
		query.declareParameters(User.class.getName() + " u, int s, int r");
		//query.declareParameters("int s");
		//query.declareParameters("int rt");
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("u", new User(loginName));
		params.put("s", DONE);
		params.put("r", Task.ONE_TIME);
		lsTask = (List<Task>) query.executeWithMap(params);
		pm.currentTransaction().begin();
		pm.deletePersistentAll(lsTask);
		pm.currentTransaction().commit();
		pm.flush();
		pm.close();
	}

	public List<Task> listTask() {
		TaskDao dao = new TaskDao(Task.class);
		return dao.findAll();
	}

	public List<Task> listTaskByUserId(String loginName) {
		List<Task> lsTask = null;
		TaskDao dao = new TaskDao(Task.class);
		lsTask = dao.findByUserId(loginName);
		log.fine("listTaskByUserId=" + loginName + " ,size=" + lsTask.size());
		return lsTask;
	}

	public List<Task> listTaskByRange(String loginName, long fromIncl,
			long toExcl) {
		List<Task> lsTask = null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery("select from " + Task.class.getName()
				+ " where ownedUser == u order by dueDate asc");
		query.declareParameters(User.class.getName() + " u");
		query.setRange(fromIncl, toExcl);
		Map params = new HashMap();
		params.put("u", new User(loginName));
		lsTask = (List<Task>) query.executeWithMap(params);
		log.fine("login[" + loginName + "] - listTaskByRange " + fromIncl
				+ " to " + toExcl + " size=" + lsTask.size());
		pm.retrieveAll(lsTask);
		pm.close();
		return lsTask;
	}

	public int countTask(String loginName) {
		List<Task> lsTask = null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery("select from " + Task.class.getName()
				+ " where ownedUser == u");
		query.declareParameters(User.class.getName() + " u");
		lsTask = (List<Task>) query.execute(new User(loginName));
		int size = lsTask.size();
		log.fine("login[" + loginName + "] countTask size=" + size);
		pm.close();
		return size;
	}

	public List<Task> searchTask(String loginName, String startsWith,
			long fromIncl, long toExcl) {
		if (startsWith.isEmpty()) {
			return new ArrayList<Task>();
		}
		List<Task> lsTask = null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm
				.newQuery("select from "
						+ Task.class.getName()
						+ " where ownedUser == u && this.name.startsWith(search) order by name,dueDate asc");
		query.declareParameters(User.class.getName() + " u, String search");
		Map params = new HashMap();
		params.put("u", new User(loginName));
		params.put("search", startsWith);
		query.setRange(fromIncl, toExcl);
		lsTask = (List<Task>) query.executeWithMap(params);
		log.fine("login[" + loginName + "] Search filter=" + startsWith
				+ ",fromIncl=" + fromIncl + ",toExcl=" + toExcl + ", Found "
				+ lsTask.size() + " record(s)");
		pm.retrieveAll(lsTask);
		/*
		 * for (Task t : lsTask) { t.getOwnedUserId(); // fetch user
		 * t.toString(); // fetch task attr; }
		 */
		pm.close();
		return lsTask;
	}

	public int countBySearchTask(String loginName, String startsWith) {
		if (startsWith.isEmpty()) {
			return 0;
		}
		List<Task> lsTask = null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery("select from " + Task.class.getName()
				+ " where ownedUser == u && this.name.startsWith(search)");
		query.declareParameters(User.class.getName() + " u, String search");
		Map params = new HashMap();
		params.put("u", new User(loginName));
		params.put("search", startsWith);
		lsTask = (List<Task>) query.executeWithMap(params);
		int size = lsTask.size();
		log.fine("login[" + loginName + "] count by search task size=" + size);
		pm.close();
		return size;
	}

	public List<Task> listTaskByState(String loginName, int state) {
		List<Task> lsTask = null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery("select from " + Task.class.getName()
				+ " where ownedUser == u && state == s");
		query.declareParameters(User.class.getName() + " u, int s");
		Map params = new HashMap();
		params.put("u", new User(loginName));
		params.put("s", state);
		lsTask = (List<Task>) query.executeWithMap(params);
		pm.retrieveAll(lsTask);
		pm.close();
		return lsTask;
	}

	/**
	 * List all repeat task (repeat type != 0)
	 * 
	 * @return
	 */
	public List<Task> listRepeatTask(PersistenceManager pm) {
		List<Task> tasks = null;
		Query query = pm.newQuery("select from " + Task.class.getName()
				+ " where repeatType != rt");
		query.declareParameters("int rt");
		Map params = new HashMap();
		params.put("rt", Task.ONE_TIME);
		tasks = (List<Task>) query.executeWithMap(params);
		pm.retrieveAll(tasks);
		return tasks;
	}
	
	public void saveTask(PersistenceManager pm,List<Task> tasks){
		pm.makePersistentAll(tasks);
	}
	
	private int getStateCode(String state) {
		int code = -1;
		if ("DONE".equalsIgnoreCase(state)) {
			code = DONE;
		}
		if ("ONGOING".equalsIgnoreCase(state)) {
			code = ONGOING;
		}
		if ("TIMEOUT".equalsIgnoreCase(state)) {
			code = TIMEOUT;
		}
		return code;
	}

}
